import java.io.EOFException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PushbackReader;
import java.nio.charset.CharacterCodingException;

public class MyPushbackReader extends PushbackReader
{
	/*
	 BOM = Byte Order Mark
	 FE FF 00 3C = UTF-16, big-endian
	 FF FE 3C 00 = UTF-16, little-endian
	 EF BB BF    = UTF-8
	*/

	public static final char UTF_8_BOM = '\uFEFF';
	
	private int lineNumber = 1;
	
	public MyPushbackReader(String filename) throws IOException
	{
		super(new InputStreamReader(new FileInputStream(filename), "UTF-8"));
		
		int i = read();
		
		if (i == -1)
		{
			throw new EOFException();
		}
		
		char c = (char) i;
		
		if (c != UTF_8_BOM)
		{
			unread(i);
			System.err.println("NO BOM FOUND!");
		}
	}
	
	public String nextToken() throws IOException
	{
		int i = nextTokenChar();
		
		if (i == -1)
		{
			throw new EOFException();
		}
		
		char c = (char) i;
		
		String token = "" + c;
		
		if (c == '<')
		{
			int offset = -1, ignore = -1;
			
			String[] ignoreStartTags = {"<![CDATA[", "<!--"}, ignoreEndTags = {"]]>", "-->"};
			
			do
			{
				offset++;
				
				while ((i = read()) != -1)
				{
					token += (char) i;
					
					if (i == '>')
					{
						break;
					}
				}
				/*
			//	System.out.println(token);
			//	System.out.flush();
				*/
				if (offset < 10 && ignore == -1)
				{
					for (int key = 0; key < 2; key++)
					{
						if (token.startsWith(ignoreStartTags[key]))
						{
							ignore = key;
							
							break;
						}
					}
				}
			}
			while (ignore != -1 && !token.endsWith(ignoreEndTags[ignore]));
		}
		else
		{
			while ((i = read()) != -1 && i != '<')
			{
				token += (char) i;
			}
			
			// We need the < not only to determine when to stop, but also to
			// determine that a new token starts, so we need to put it back.
			unread(i);
		}
		
		if (token.isEmpty())
		{
			return null;
		}
		
		return token;
	}
	
	private int nextTokenChar() throws IOException
	{
		int i = read();
		
		if (i == -1)
		{
			return -1;
		}
		
		switch (i)
		{
			case 10: // new line
				lineNumber++;
			case 9: // tab
			case 13: // carriage return
			case 32: // space
				return nextTokenChar();
		}
		
		return i;
	}
	
	public int getLineNumber()
	{
		return lineNumber;
	}
}
